package com.android.dx.ppx.api;

import android.util.Log;

import com.android.dx.ppx.BuildConfig;
import com.android.dx.ppx.app.App;
import com.android.dx.ppx.model.HttpResponse;
import com.ihsanbal.logging.Level;
import com.ihsanbal.logging.LoggingInterceptor;
import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;

import java.lang.reflect.ParameterizedType;
import java.net.HttpURLConnection;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.ObservableSource;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import okhttp3.Headers;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.internal.platform.Platform;
import retrofit2.Converter;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * Author: Ligang
 * Date:  2019/8/30
 * Description:
 */
public class ApiManager<ApiService> {
    private static final String TAG = ApiManager.class.getName();
    public static final long DEFAULT_READ_TIMEOUT_MILLIS = 12 * 1000;
    public static final long DEFAULT_WRITE_TIMEOUT_MILLIS = 12 * 1000;
    public static final long DEFAULT_CONNECT_TIMEOUT_MILLIS = 12 * 1000;
    protected ApiService apiService;

    public ApiManager() {
        init();
    }

    protected void init() {
        Retrofit.Builder builder = new Retrofit.Builder();
        if (baseUrl() != null) {
            builder.baseUrl(baseUrl());
        }
        Converter.Factory factory = converterFactory();
        if (factory != null) {
            builder.addConverterFactory(factory);
        }
        builder.addCallAdapterFactory(RxJava2CallAdapterFactory.create());
        builder.client(initOkHttp());
        Retrofit retrofit = builder.build();
        apiService = retrofit.create((Class<ApiService>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
    }

    protected OkHttpClient newSimpleOkHttp() {
        OkHttpClient.Builder mOkHttpClientBuilder = new OkHttpClient.Builder()
                .readTimeout(DEFAULT_READ_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
                .writeTimeout(DEFAULT_WRITE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
                .connectTimeout(DEFAULT_CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
        if (BuildConfig.DEBUG) {
            //打印网络请求日志
            LoggingInterceptor httpLoggingInterceptor = new LoggingInterceptor.Builder()
                    .loggable(true)
                    .setLevel(Level.BASIC)
                    .log(Platform.INFO)
                    .request("Request")
                    .response("Response")
                    .build();
            mOkHttpClientBuilder.addInterceptor(httpLoggingInterceptor);
        }
        return mOkHttpClientBuilder.build();
    }

    protected OkHttpClient initOkHttp() {
        OkHttpClient.Builder mOkHttpClientBuilder = new OkHttpClient.Builder()
                .readTimeout(DEFAULT_READ_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
                .writeTimeout(DEFAULT_WRITE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
                .connectTimeout(DEFAULT_CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
                .addInterceptor((chain) -> {
                    Request.Builder builder = chain.request()
                            .newBuilder()
                            .addHeader("Content-Type", "application/json; charset=utf-8")
                            .addHeader("Connection", "keep-alive");
//                    if (!TextUtils.isEmpty(AppDataHolder.getInstance().getCookie())) {
//                        builder.addHeader("Cookie", AppDataHolder.getInstance().getCookie());
//                    }
                    Response response = chain.proceed(builder.build());
                    if (response != null && response.code() == HttpURLConnection.HTTP_OK) {
                        Headers headers = response.headers();
                        if (headers != null) {
                            String cookie = "";
                            for (int i = 0, size = headers.size(); i < size; i++) {
                                if ("Set-Cookie".equalsIgnoreCase(headers.name(i))) {
                                    cookie += headers.value(i);
                                    cookie += ";";
                                }
                            }
//                            if (cookie.contains("SessionId") && cookie.contains("AccessToken")) {
//                                AppDataHolder.getInstance().setCookie(cookie.substring(0, cookie.length() - 1));
//                            }
                        }
                    }
                    return response;
                });

        if (BuildConfig.DEBUG) {
            //打印网络请求日志
            LoggingInterceptor httpLoggingInterceptor = new LoggingInterceptor.Builder()
                    .loggable(BuildConfig.DEBUG)
                    .setLevel(Level.BASIC)
                    .log(Platform.INFO)
                    .request("Request")
                    .response("Response")
                    .build();
            mOkHttpClientBuilder.addInterceptor(httpLoggingInterceptor);
        }
        return mOkHttpClientBuilder.build();
    }

    protected String baseUrl() {
        return BuildConfig.BASE_URL;
    }

    protected Converter.Factory converterFactory() {
        return GsonConverterFactory.create();
    }

    protected RequestBody buildBody(Object obj) {
        RequestBody body;
        if (obj instanceof String) {
            body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), obj.toString());
        } else {
            body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), App.gson.toJson(obj));
        }
        return body;
    }

    protected <T extends HttpResponse> Observable<T> request(final Observable<T> resultVoObservable) {
        return request(false, resultVoObservable);
    }

    protected <T extends HttpResponse> Observable<T> request(boolean noneSchedulers, final Observable<T> resultVoObservable) {
        if (noneSchedulers) {
            return resultVoObservable
                    .onErrorResumeNext(doOnHttpException(resultVoObservable))
                    .flatMap(new Function<HttpResponse, ObservableSource<T>>() {
                        @Override
                        public ObservableSource<T> apply(HttpResponse httpResponse) throws Exception {
                            return flatResponse(httpResponse);
                        }
                    })
                    .onErrorResumeNext(doOnServerResponseError(resultVoObservable));
        }
        return resultVoObservable
                .onErrorResumeNext(doOnHttpException(resultVoObservable))
                .flatMap(new Function<HttpResponse, ObservableSource<T>>() {
                    @Override
                    public ObservableSource<T> apply(HttpResponse httpResponse) throws Exception {
                        return flatResponse(httpResponse);
                    }
                })
                .onErrorResumeNext(doOnServerResponseError(resultVoObservable))
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }

    private <T extends HttpResponse> Function<Throwable, ObservableSource<T>> doOnHttpException(final Observable<T> observable) {
        return new Function<Throwable, ObservableSource<T>>() {
            @Override
            public ObservableSource<T> apply(Throwable throwable) throws Exception {
                return Observable.error(throwable);
            }
        };
    }


    private <T extends HttpResponse> Function<Throwable, ObservableSource<T>> doOnServerResponseError(final Observable<T> observable) {
        return new Function<Throwable, ObservableSource<T>>() {
            @Override
            public ObservableSource<T> apply(Throwable throwable) throws Exception {
                if (throwable instanceof ServerResponseError) {
                    ServerResponseError serverResponseError = (ServerResponseError) throwable;
//                    if (!AuthUtil.authCheck(serverResponseError.getAuthStatus())) {
//                        PhoneTipUtils.buildAppTipItem("doOnServerResponseError：开始自动登录");
//                        if (AppDataHolder.getInstance().getLoginRequest() != null) {
//                            return ApiClient.instance().login(AppDataHolder.getInstance().getLoginRequest())
//                                    .flatMap(new Function<HttpResponse<ResponseLogin>, ObservableSource<T>>() {
//                                        @Override
//                                        public ObservableSource<T> apply(HttpResponse<ResponseLogin> responseLoginHttpResponse) throws Exception {
//                                            PhoneTipUtils.buildAppTipItem("doOnServerResponseError：自动登录成功");
//                                            return observable.retry();
//                                        }
//                                    });
//                        }
//
//                    }

                }
                return Observable.error(throwable);
            }
        };
    }

    /**
     * 对网络接口返回的ResultVo进行分割操作
     */
    private <T> Observable<T> flatResponse(final HttpResponse resultVo) {
        return Observable.create(new ObservableOnSubscribe<T>() {

            @Override
            public void subscribe(ObservableEmitter<T> e) throws Exception {
                Log.d("ApiClient", resultVo.toString());

//                if (!AuthUtil.authCheck(resultVo.getAuthStatus())) {
//                    //如果失效 就自动登陆，再继续之前的接口
//                    DebugFileUtils.appendStartupProcess("cookie失效啦");
//                    PhoneTipUtils.buildAppTipItem("cookie失效了");
//                }

                if (resultVo.isSuccess()) {
                    e.onNext((T) resultVo);
                } else {
                    e.onError(new ServerResponseError(resultVo));
                }
                e.onComplete();
            }
        });
    }
}
